package study.javaee.practice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import study.javaee.practice.common.api.ResultCode;
import study.javaee.practice.common.exception.Throws;
import study.javaee.practice.dao.UserDao;
import study.javaee.practice.entity.User;
import study.javaee.practice.entity.UserDetailsEntity;
import study.javaee.practice.service.UserCacheService;
import study.javaee.practice.service.UserService;
import study.javaee.practice.utils.security.MyPasswordEncoder;

import java.util.Objects;

@Service
public class UserServiceImpl implements UserService {

    UserDao userDao;
    UserCacheService userCacheService;
    final MyPasswordEncoder passwordEncoder;

    @Autowired
    public UserServiceImpl(UserDao userDao, UserCacheService userCacheService, MyPasswordEncoder passwordEncoder) {
        this.userDao = userDao;
        this.userCacheService = userCacheService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public User getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication==null)
            return null;
        Object principal = authentication.getPrincipal();
        if (!(principal instanceof UserDetailsEntity)){
            return null;
        }
        //更新当前用户在spring security中的信息
        UserDetailsEntity entity = ((UserDetailsEntity) principal);
        return entity.getUser();
    }

    @Override
    public User getCurrentUser(boolean refreshSecurityUser) {
        User oldUser = getCurrentUser();
        User user = null;
        //更新spring security中的当前用户权限
        if (refreshSecurityUser){
            assert oldUser!=null;
            user  = userDao.selectById(oldUser.getId());
            UserDetailsEntity entity = new UserDetailsEntity(user);
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(entity, null, entity.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            entity.setUser(user);
        }
        return user;
    }

    @Override
    public User getUserById(Integer id) {
        return id==null?null: userDao.selectById(id);
    }

    @Nullable
    @Override
    public User getUserByEmail(String email) {
        User user = userCacheService.getUser(email);
        if (user == null){
            QueryWrapper<User> userWrapper = new QueryWrapper<>();
            userWrapper.eq("email", email);
            user = userDao.selectOne(userWrapper);
            userCacheService.setUser(email, user); // 写入缓存
        }
        return user;
    }

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        User user = getUserByEmail(s);
        return user==null?null:new UserDetailsEntity(user);
    }

    @Override
    public void addUser(User user) {
        if (hasUser(user.getEmail())){
            Throws.clientFailed("邮箱账号已存在");
        }
        user.setPassword(passwordEncoder.encode(user.getPassword(), user.getEmail()));
        if (userDao.insert(user)==0){
            Throws.clientFailed("未知错误");
        }
    }

    @Override
    public boolean hasUser(String email) {
        return getUserByEmail(email)!=null;
    }

    @Override
    public boolean hasUser(Integer userId) {
        return getUserById(userId) != null;
    }

    @Override
    public IPage<User> getUsers(User user, long page, long pageSize) {
        Page<User> userPage = new Page<>(page, pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (user.getType()!=null){
            queryWrapper.eq("type", user.getType());
        }
        if (!StringUtil.isNullOrEmpty(user.getName())){
            queryWrapper.like("name", user.getName());
        }
        queryWrapper.select(User.class, tableFieldInfo -> !tableFieldInfo.getColumn().equals("password"));
        return userDao.selectPage(userPage, queryWrapper);
    }

    public void updateUser(User user) {
        if(!hasUser(user.getId())){
            Throws.clientFailed("用户不存在!");
        }
        if (StringUtil.isNullOrEmpty(user.getPassword())){
            user.setPassword(null);
        }else{ // 密码为空表示不修改密码，需设置密码字段为null
            user.setPassword(passwordEncoder.encode(user.getPassword(),user.getEmail()));
        }
        if (userDao.updateById(user)!=0){  // 删除过期缓存
            userCacheService.deleteUser(user.getEmail());
        }
    }

    @Override
    public void updateUserById(User user, int id) {
        user.setId(id);
        updateUser(user);
    }

    @Override
    public void updateCurrentUser(User user) {
        User currentUer = getCurrentUser();
        assert currentUer != null;
        if (!Objects.equals(user.getId(), currentUer.getId()) || !Objects.equals(user.getType(), currentUer.getType())
           || !Objects.equals(user.getEmail(),currentUer.getEmail())
        ){
            Throws.failed(ResultCode.FORBIDDEN);
        }
        updateUser(user);
    }
}
